package nachos.vm;

import nachos.machine.*;
import nachos.threads.*;
import nachos.userprog.*;
import nachos.vm.*;

/**
 * A kernel that can support multiple demand-paging user processes.
 */
public class VMKernel extends UserKernel {
    public OpenFile swapFile;
    /**
     * Method that copies one page from swap to memory.
     * @param swapPage
     * @param ppn
     * @return true on successfull
     */
    public boolean getPageFromSwap(int swapPage,int ppn){
        if(ppn >= Machine.processor().getNumPhysPages())
            return false;
        Lib.debug(dbgVM, "Getting page from disk - ppn: " + ppn + " swapOffset: " + swapPage);
        byte[] memory = Machine.processor().getMemory();
        this.swapFile.seek(Processor.makeAddress(swapPage,0));
        int read= this.swapFile.read(memory, Processor.makeAddress(ppn, 0), Processor.pageSize);
        return read == Processor.pageSize;
    }
    /**
     * Method that copies one page to the swap from memory.
     * @param swapPage
     * @param ppn
     * @return true on successfull
     */
    public boolean savePageToSwap(int swapPage, int ppn){
        if(ppn >= Machine.processor().getNumPhysPages())
            return false;
        Lib.debug(dbgVM, "Saving page to disk - ppn: " + ppn + " swapOffset: " + swapPage);
        byte[] memory = Machine.processor().getMemory();
        this.swapFile.seek(Processor.makeAddress(swapPage,0));
        int write  = this.swapFile.write(memory,Processor.makeAddress(ppn, 0), Processor.pageSize);
        return write == Processor.pageSize;
    }
    /**
     * Allocate a new VM kernel.
     */
    public VMKernel() {
	super();
    }

    /**
     * Initialize this kernel.
     */
    @Override
    public void initialize(String[] args) {
        super.initialize(args);
        this.swapFile = Machine.stubFileSystem().open("pagefile.sys", true);
        if (this.swapFile == null){
             Lib.debug(dbgVM, "Couldn't create pagefile.sys");
             this.terminate();
        } 
    }

    /**
     * Test this kernel.
     */	
    @Override
    public void selfTest() {
	super.selfTest();
    }

    /**
     * Start running user programs.
     */
    @Override
    public void run() {
	super.run();
    }
    
    /**
     * Terminate this kernel. Never returns. Deletes the swap file.
     */
    @Override
    public void terminate() {
        this.swapFile.close();
        Machine.stubFileSystem().remove("pagefile.sys");
        VMKernel.alarm.waitUntil(1000);
	super.terminate();
    }

    // dummy variables to make javac smarter
    private static VMProcess dummy1 = null;

    private static final char dbgVM = 'v';
}
